package com.gateway.filters;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gateway.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebSession;
import reactor.core.publisher.Mono;

import javax.servlet.http.HttpSession;
import java.util.*;

/**
 * @Description: TODO
 * @Author: mis_wu
 * @Date: 2022/5/4
 * 网关鉴权过滤器
 **/
@Component
@Slf4j
public class AuthorizeFilter implements GlobalFilter, Ordered {

    private static final String AUTHORIZE_TOKEN = "token";
    private static final String AUTHORIZE_JWT = "movie-jwt";
    private static final String ADMIN_LOGIN_PATH = "/admins-services/adminlogin";
    private static final String USERS_LOGIN_PATH = "/users-services/userlogin";
    private static final String USERS_REGISTER_PATH = "/users-services/userregister";
    private static final String MOVIE_USERS_LOGIN_PATH = "/Movie-Users-Services/movieUserLogin";
    private static final String MOVIE_USERS_REGISTER_PATH = "/Movie-Users-Services/movieUserRegister";
    private static final String VIDEOS_FREE_MOVIE_PATH = "/videos-services/queryCommonsMovies";
    private static final String AUTHORIZE_ERROR = "用户信息错误,鉴权失败!!!";
    private static final String AUTHORIZE_PERMISSIONS = "权限不足,请登录!!!";
    private static final String AUTHORIZE_EXPIRE = "令牌过期,请退出重新登录!!!";
    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("----------------进入jwt网关鉴权过滤器----------------");
        //获取请求
        ServerHttpRequest request = exchange.getRequest();
        //获取响应
        ServerHttpResponse response = exchange.getResponse();
        //请求路径
        String requestPath = request.getURI().getPath();
        List<String> paths = new ArrayList<>();
        paths.add(ADMIN_LOGIN_PATH);
        paths.add(USERS_LOGIN_PATH);
        paths.add(USERS_REGISTER_PATH);
        paths.add(VIDEOS_FREE_MOVIE_PATH);
        paths.add(MOVIE_USERS_LOGIN_PATH);
        paths.add(MOVIE_USERS_REGISTER_PATH);
        //需要放行的请求路径(登录、注册等)
        for (String path : paths) {
            if (requestPath.contains(path)){
                return chain.filter(exchange);
            }
        }
        //获取请求头
        HttpHeaders headers = request.getHeaders();
        //获取请求头中的令牌(秘钥)
        String token = headers.getFirst(AUTHORIZE_TOKEN);
        //判断请求头中是否有令牌
        if (StringUtils.isEmpty(token)){
            //响应中放入返回的状态吗, 没有权限访问
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //return response.setComplete();
            return responseContext(response,AUTHORIZE_PERMISSIONS);
        }
        log.info("请求头jwt信息:{}",token);
        //如果请求头中有令牌则解析令牌
        try {
            //token令牌解密
            Claims claims = JwtUtil.parseJWT(token);
            String jwt = claims.getSubject();
            log.info("解密后的jwt令牌:{}",jwt);
            if (!Objects.equals(jwt,redisTemplate.opsForValue().get(AUTHORIZE_JWT))){
                //jwt令牌不对
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                //设置响应内容
                return responseContext(response,AUTHORIZE_ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //解析jwt令牌出错, 说明令牌过期或者伪造等不合法情况出现
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //这里可不用return,交给GlobalExceptionConfiguration处理;return response.setComplete()是空模板
            return responseContext(response,AUTHORIZE_EXPIRE);
        }
        log.info("----------------结束jwt网关鉴权过滤器----------------");
        //放行
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * 设置响应内容
     * @param response
     */
    public Mono<Void> responseContext(ServerHttpResponse response,String msg){
        Map<Object, Object> map = new HashMap<>(8);
        response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory bufferFactory = response.bufferFactory();
            map.put("msg",msg);
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                return bufferFactory.wrap(objectMapper.writeValueAsBytes(map));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            return null;
        }));
        return null;
    }
}
